package com.hfb.io.netty.chat;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;


/**
 * 聊天室 server
 */
public class ChatServer {

    private int port;

    ChatServer(int port) throws InterruptedException {
        this.port = port;
        start();
    }

    private void start() throws InterruptedException {
        // 2个线程组，含义子线程 NioEventLoop的个数是默认是CPU核数的2倍
        EventLoopGroup bossGrourp = new NioEventLoopGroup(1);
        EventLoopGroup workGrourp = new NioEventLoopGroup(8);
        try {
            // 服务端的启动对象
            ServerBootstrap bootstrap = new ServerBootstrap();
            // 链式编程配置参数
            bootstrap.group(bossGrourp, workGrourp) // 配置2个线程组
            // 使用  NioServerSocketChannel 作为服务端的通道实现
                     .channel(NioServerSocketChannel.class)
                // 初始化服务器连接队列的大小。server端处理连接请求是顺序的，故同一时间只能处理一个连接
                // 多个客户端同时来的时候，服务端将不能处理的连接放入队列中
                     .option(ChannelOption.SO_BACKLOG, 1024)
                    .option(ChannelOption.TCP_NODELAY, true) // 不延迟，消息立即发送
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 长连接
                     .childHandler(new ChannelInitializer<SocketChannel>() {
                         @Override
                         protected void initChannel(SocketChannel ch) throws Exception {
                             // 对 workGroup 的 SocketChannel 设置处理器
                             ChannelPipeline pipeline = ch.pipeline();
                             // 加入特殊分隔符解码器
                             pipeline.addLast(
                                 new DelimiterBasedFrameDecoder(
                                     1024,
                                     Unpooled.copiedBuffer("_".getBytes())));


                             // 加入解码器
                             pipeline.addLast("decoder", new StringDecoder());
                             // 加入编码器
                             pipeline.addLast("encoder", new StringEncoder());
                             // 添加自己的业务处理器
                             pipeline.addLast(new ChatServerHandler());
                         }
                     });
            System.err.println("chat server startting ...");

            // 绑定一个端口并同步，生成一个ChannelFuture异步对象 通过 isDone()方法可判断异步执行情况
            // 启动服务器并绑定端口，bind是异步的，sync是等待异步操作执行完毕
            ChannelFuture cf = bootstrap.bind(port).sync();
            if (cf.isSuccess()) {
                System.err.println("chat server started, port:"+port);
            }
            // 关闭连接
            cf.channel().closeFuture().sync();
        } finally {
            bossGrourp.shutdownGracefully();
            workGrourp.shutdownGracefully();
        }

    }

    public static void main(String[] args) throws InterruptedException {
        int port = 9100;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        }
        new ChatServer(port);
    }


}
